import datetime
import random
import re
import ipaddress

from prettytable import PrettyTable

from interface import Interface


# 验证IP地址格式是否正确
def validate_ip_with_subnet(ip_with_subnet):
    # 定义用于验证IPv4地址和子网掩码的正则表达式
    pattern = r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/\d{1,2}$'
    # 如果匹配成功，返回True，否则返回False
    if re.match(pattern, ip_with_subnet):
        # 进一步验证子网掩码是否在0-32之间
        subnet_mask = int(ip_with_subnet.split('/')[-1])
        if 0 <= subnet_mask <= 32:
            return True
    return False


# 判断目-ip是否会命中路由
def check_aggregate_route(destination_ip, aggregate_route):
    destination_network = ipaddress.ip_network(destination_ip, strict=False)
    aggregate_network = ipaddress.ip_network(aggregate_route, strict=False)

    # 检查目标地址是否在聚合路由内
    return destination_network.subnet_of(aggregate_network)


# 格式化snmp的消息为路由表
# snmp_message_routes: 路由信息 = proto
def normalize_route_info(snmp_message_routes):
    prefix = ".1.3.6.1.2.1.4.24.4.1.6."
    route_table = []
    lines = snmp_message_routes.split('\n')
    for line in lines:
        if line.strip():
            parts = line.strip().split(' = ')
            destination = parts[0].replace(prefix, '')
            destination_parts = destination.split('.')
            destination_ip = ".".join(destination_parts[:4])
            net_mask = ".".join(destination_parts[4:8])
            nexthop = ".".join(destination_parts[9:13])
            proto_type = parts[1].split(': ')[1]
            interface = ""
            route_table.append({
                "destination": destination_ip,
                "net_mask": net_mask,
                "nexthop": nexthop,
                "interface": interface,
                "proto_type": proto_type
            })
    return route_table


# 格式化snmp的消息为路由表
# snmp_message_routes: 路由信息 = 出接口index
def normalize_route_info_interface_index(snmp_message_routes):
    prefix = ".1.3.6.1.2.1.4.24.4.1.5."
    route_table = []
    lines = snmp_message_routes.split('\n')
    for line in lines:
        if line.strip():
            parts = line.strip().split(' = ')
            destination = parts[0].replace(prefix, '')
            destination_parts = destination.split('.')
            destination_ip = ".".join(destination_parts[:4])
            net_mask = ".".join(destination_parts[4:8])
            nexthop = ".".join(destination_parts[9:13])
            interface_index = parts[1].split(': ')[1]
            route_table.append({
                "destination": destination_ip,
                "net_mask": net_mask,
                "nexthop": nexthop,
                "interface": interface_index,
                "proto_type": ""
            })
    return route_table


# 格式化snmp的消息为接口列表
def normalize_interface_ip_index(snmp_message_interface):
    prefix = ".1.3.6.1.2.1.4.20.1.2."
    interface_ip_index_list = []
    lines = snmp_message_interface.split('\n')
    for line in lines:
        if line.strip():
            parts = line.strip().split(' = ')
            ip = parts[0].replace(prefix, '')
            index = parts[1].replace("INTEGER: ", "")
            interface_ip_index_list.append({
                "index": index,
                "name": "undefined_name",
                "ip": ip,
                "net_mask": "undefined_netmask"
            })
    return interface_ip_index_list


# 格式化snmp的消息为接口列表
def normalize_interface_index_name(snmp_message_interface):
    prefix = ".1.3.6.1.2.1.31.1.1.1.18."
    interface_index_name_list = []
    lines = snmp_message_interface.split('\n')
    for line in lines:
        if line.strip():
            parts = line.strip().split(' = ')
            index = parts[0].replace(prefix, '')
            name = parts[1].replace("STRING: ", "").replace("\"", "")
            interface_index_name_list.append({
                "index": index,
                "name": name,
                "ip": "undefined_ip",
                "net_mask": "undefined_netmask"
            })
    return interface_index_name_list


# 格式化snmp的消息为接口列表
def normalize_interface_ip_netmask(snmp_message_interface):
    prefix = ".1.3.6.1.2.1.4.20.1.3."
    interface_ip_netmask_list = []
    lines = snmp_message_interface.split('\n')
    for line in lines:
        if line.strip():
            parts = line.strip().split(' = ')
            ip = parts[0].replace(prefix, '')
            net_mask = parts[1].replace("IpAddress: ", "")
            interface_ip_netmask_list.append({
                "index": "undefined_index",
                "name": "undefined_name",
                "ip": ip,
                "net_mask": net_mask
            })
    return interface_ip_netmask_list


# 格式化snmp的消息为接口列表
def normalize_interface_info(snmp_message):
    interface_list = []
    return interface_list


# 测试路由匹配规则是否正确
def test_check_aggregate_route():
    destination_ip = '172.16.18.1/23'
    aggregate_route = '172.16.8.1/10'
    if check_aggregate_route(destination_ip, aggregate_route):
        print("目标地址在聚合路由内")
    else:
        print("目标地址不在聚合路由内")


# 路由表中proto字段的含义及其对应的index
def check_route_proto_type(proto_type):
    if "1" == proto_type:
        return "other"
    if "2" == proto_type:
        return "reject"
    if "3" == proto_type:
        return "local"
    if "4" == proto_type:
        return "remote"
    return "other"


def create_interface_object_list_from_init_parameters_list(interface_init_parameter_list):
    interface_object_list = []
    for interface_init_parameter in interface_init_parameter_list:
        interface = Interface()
    return []


'''
todo wangfei 优化逻辑:
匹配安全策略时，一共有： rule name ,source-zone , source-address, destination-zone, destination-address,action 几个条目，需考虑某条目缺失时的匹配情况
'''


# 确认权限范围是否过大
def authorization_confirm(device_name, param, exist_secure_policy):
    if len(param) > 0:
        print("设备{}的安全策略{}与需求接近，可以修改，但是需确认:\n{}".format(device_name, exist_secure_policy["rule name"],
                                                        exist_secure_policy))
        user_input = input("\033[1;31m温馨提示：" + ",".join(param) + "权限范围较大（为any），生成【修改】会有一定风险。请确认是否生成【修改】！"
                           + "\n 回车 在此策略上进行操作      N 不在此条策略上进行操作   请输入决定：\033[0m")
        if user_input == 'N' or user_input == 'n':
            return False
    else:
        print("设备{}的安全策略{}与需求接近，可以修改:\n{}".format(device_name, exist_secure_policy["rule name"],
                                                  exist_secure_policy))
    return True


# 确认网络策略：
# 1、完全匹配-pass
# 2、大部分匹配（指只有一条不匹配）-edit
# 3、完全不匹配-create
def check_secure_policy(secure_route_list_, origin_ip_, destination_ip_):
    firewall_need_new_policy = []
    firewall_need_edit_policy = []
    # 确认路由中涉及的防火墙设备及其接口（安全区域）
    for secure_route_detail in secure_route_list_:
        secure_device = secure_route_detail["device"]
        interface_in = secure_route_detail["interface_in"]
        interface_out = secure_route_detail["interface_out"]
        zone_in = interface_in.zone
        zone_out = interface_out.zone
        # 确认是否存在符合的路由
        exist_secure_policy_list = secure_device.secure_policy_info
        # 比较，源区域是否被已有策略的源区域覆盖
        # 比较，目区域是否被已有策略的目区域覆盖
        # 比较，源地址是否为已有策略的源地址的子网
        # 比较，目地址是否为已有策略的目地址的子网
        # 比较action是否为permit
        if len(exist_secure_policy_list) == 0:
            firewall_need_new_policy.append(secure_route_detail)
            print("设备{}的所有安全策略均不满足当前需求且无法进行修改，建议新增安全策略".format(secure_device.device_name))
            break
        no_total_match = True
        for exist_secure_policy in exist_secure_policy_list:
            excessive_permissions_warnings = []
            match_count = 0
            edit_key = ""
            exist_secure_policy_source_zone = exist_secure_policy["source-zone"]
            # 比较，源区域是否被已有策略的源区域覆盖
            if zone_in in exist_secure_policy_source_zone or len(exist_secure_policy_source_zone) < 1:
                if len(exist_secure_policy_source_zone) < 1:
                    excessive_permissions_warnings.append("source-zone")
                match_count += 1
            else:
                edit_key = "source-zone"
            exist_secure_policy_source_address = exist_secure_policy["source-address"]
            # 比较，源地址是否为已有策略的源地址的子网
            if len(exist_secure_policy_source_address) < 1:
                excessive_permissions_warnings.append("source-address")
                match_count += 1
            else:
                for exist_secure_policy_source_address_formatted_element in \
                        [(source_address["ip"] + "/" + source_address["mask"])
                         for source_address in exist_secure_policy_source_address]:
                    if check_aggregate_route(origin_ip_, exist_secure_policy_source_address_formatted_element):
                        match_count += 1
                        break
                    else:
                        edit_key = "source-address"
            exist_secure_policy_destination_zone = exist_secure_policy["destination-zone"]
            # 比较，目区域是否被已有策略的目区域覆盖
            if zone_out in exist_secure_policy_destination_zone or len(exist_secure_policy_destination_zone) < 1:
                if len(exist_secure_policy_destination_zone) < 1:
                    excessive_permissions_warnings.append("destination-zone")
                match_count += 1
            else:
                edit_key = "destination-zone"
            # 比较，目地址是否为已有策略的目地址的子网
            exist_secure_policy_destination_address = exist_secure_policy["destination-address"]
            if len(exist_secure_policy_destination_address) < 1:
                excessive_permissions_warnings.append("destination-address")
                match_count += 1
            else:
                for exist_secure_policy_destination_address_formatted_element in [
                    (destination_address["ip"] + "/" + destination_address["mask"])
                    for destination_address in exist_secure_policy_destination_address
                ]:
                    if check_aggregate_route(destination_ip_,
                                             exist_secure_policy_destination_address_formatted_element):
                        match_count += 1
                        break
                    else:
                        edit_key = "destination-address"
            # exist_secure_policy_rule_name = exist_secure_policy["rule name"]
            exist_secure_policy_action = exist_secure_policy["action"]
            # 比较action是否为permit
            if exist_secure_policy_action == "permit":
                match_count += 1
            else:
                edit_key = "action"
            if match_count == 5:
                print("设备{}的安全策略{}完全满足当前需求，策略具体为：\n{}"
                      .format(secure_device.device_name, exist_secure_policy["rule name"], str(exist_secure_policy)))
                no_total_match = False
                break
            elif match_count == 4 and authorization_confirm(secure_device.device_name, excessive_permissions_warnings,
                                                            exist_secure_policy):
                firewall_need_edit_policy.append(
                    {"secure_route_detail": secure_route_detail, "old_policy": exist_secure_policy,
                     "edit_key": edit_key})
                break
            else:
                print("设备{}的安全策略{}不满足当前需求，继续确认下一条".format(secure_device.device_name, exist_secure_policy["rule name"]))
                continue
        if ((len(firewall_need_edit_policy) + len(firewall_need_new_policy)) == 0) and no_total_match:
            print("设备{}的所有安全策略均不满足当前需求且无法进行修改，建议新增安全策略".format(secure_device.device_name))
            firewall_need_new_policy.append(secure_route_detail)

    return firewall_need_new_policy, firewall_need_edit_policy


# 将CIDR格式的掩码进行转换，如24 转为 255.255.255.0
def cidr_to_netmask(cidr_mask):
    # 输入验证
    try:
        cidr_mask_ = int(cidr_mask)
        if not (0 <= cidr_mask_ <= 32):
            raise ValueError("CIDR mask must be an integer between 0 and 32.")
    except ValueError:
        return str(cidr_mask)  # 如果不是有效的整数或不在范围内，返回原值

    # 将CIDR掩码转换为整数
    cidr_mask = int(cidr_mask)

    # 计算每个八位字节的网络部分位数
    netmask_parts = []
    for i in range(4):
        if cidr_mask >= 8:
            netmask_parts.append(255)
            cidr_mask -= 8
        else:
            netmask_parts.append(256 - (2 ** (8 - cidr_mask)))
            cidr_mask = 0

    # 将结果格式化为字符串并返回
    return ".".join(str(part) for part in netmask_parts)


# 格式化输出到cli的字符
def format_cli_output(headers, rows):
    table = PrettyTable()

    # set the table headers
    table.field_names = headers

    # add the rows to the table
    for row in rows:
        table.add_row(row)
    print(table)


# 随机字符串作为防火墙策略名
def firewall_policy_name(source_zone, destination_zone):
    # 获取当前日期和时间
    now = datetime.datetime.now()
    # 转化为指定格式的字符串
    date_time_str = now.strftime("%Y%m%d%H%M%S")
    # 生成一个三位随机数
    random_num = random.randint(100, 999)
    # 拼接成最终的字符串
    final_str = source_zone + "to" + destination_zone + "_" + date_time_str + str(random_num)
    return final_str


if __name__ == '__main__':
    test_check_aggregate_route()
    netmask = cidr_to_netmask("8")
    print(netmask)  # 输出: 255.255.255.0
